package org.ruoyi.common.dhuman.rpc;

import java.io.File;
import java.nio.file.Paths;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

public class FFMpegDigitalHumanFusionProcessor2 {
    private String currentDir;
    private String timestamp;
    
    public FFMpegDigitalHumanFusionProcessor2() {
        this.currentDir = Paths.get("").toAbsolutePath().toString();
        this.timestamp = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMdd_HHmmss"));
    }
    
    private java.util.Map<String, String> getFilePaths() {
        java.util.Map<String, String> paths = new java.util.HashMap<>();
        paths.put("bg", Paths.get(currentDir, "bg.png").toString());
        paths.put("result_video", Paths.get(currentDir, "result.mp4").toString());
        paths.put("output", Paths.get(currentDir, "digital_human_presentation_" + timestamp + ".mp4").toString());
        return paths;
    }
    
    /**
     * 检查FFmpeg是否可用
     */
    private boolean isFFmpegAvailable() {
        try {
            ProcessBuilder processBuilder = new ProcessBuilder("ffmpeg", "-version");
            Process process = processBuilder.start();
            int exitCode = process.waitFor();
            return exitCode == 0;
        } catch (Exception e) {
            return false;
        }
    }
    
    /**
     * 获取视频尺寸信息
     */
    private VideoInfo getVideoInfo(String videoPath) throws IOException, InterruptedException {
        List<String> command = new ArrayList<>();
        command.add("ffprobe");
        command.add("-v");
        command.add("error");
        command.add("-select_streams");
        command.add("v:0");
        command.add("-show_entries");
        command.add("stream=width,height");
        command.add("-of");
        command.add("csv=p=0");
        command.add(videoPath);
        
        ProcessBuilder processBuilder = new ProcessBuilder(command);
        Process process = processBuilder.start();
        
        StringBuilder output = new StringBuilder();
        java.util.Scanner scanner = new java.util.Scanner(process.getInputStream());
        while (scanner.hasNextLine()) {
            output.append(scanner.nextLine());
        }
        scanner.close();
        
        int exitCode = process.waitFor();
        if (exitCode != 0) {
            throw new IOException("无法获取视频信息");
        }
        
        String[] dimensions = output.toString().trim().split(",");
        if (dimensions.length >= 2) {
            return new VideoInfo(Integer.parseInt(dimensions[0]), Integer.parseInt(dimensions[1]));
        }
        
        throw new IOException("无法解析视频尺寸信息");
    }
    
    /**
     * 获取背景图片尺寸信息
     */
    private VideoInfo getbgInfo(String bgPath) throws IOException, InterruptedException {
        List<String> command = new ArrayList<>();
        command.add("ffprobe");
        command.add("-v");
        command.add("error");
        command.add("-select_streams");
        command.add("v:0");
        command.add("-show_entries");
        command.add("stream=width,height");
        command.add("-of");
        command.add("csv=p=0");
        command.add(bgPath);
        
        ProcessBuilder processBuilder = new ProcessBuilder(command);
        Process process = processBuilder.start();
        
        StringBuilder output = new StringBuilder();
        java.util.Scanner scanner = new java.util.Scanner(process.getInputStream());
        while (scanner.hasNextLine()) {
            output.append(scanner.nextLine());
        }
        scanner.close();
        
        int exitCode = process.waitFor();
        if (exitCode != 0) {
            throw new IOException("无法获取背景图片信息");
        }
        
        String[] dimensions = output.toString().trim().split(",");
        if (dimensions.length >= 2) {
            return new VideoInfo(Integer.parseInt(dimensions[0]), Integer.parseInt(dimensions[1]));
        }
        
        throw new IOException("无法解析背景图片尺寸信息");
    }
    
    /**
     * 执行FFmpeg命令进行视频融合
     */
    private void executeFFmpegCommand(List<String> command) throws IOException, InterruptedException {
        System.out.println("执行FFmpeg命令: " + String.join(" ", command));
        
        ProcessBuilder processBuilder = new ProcessBuilder(command);
        processBuilder.inheritIO(); // 继承父进程的IO，显示FFmpeg的输出
        
        Process process = processBuilder.start();
        int exitCode = process.waitFor();
        
        if (exitCode != 0) {
            throw new IOException("FFmpeg命令执行失败，退出码: " + exitCode);
        }
    }
    
    /**
     * 处理绿幕数字人PPT融合任务 - 原有方法保持不变
     */
    public void processGreenScreenDigitalHumanFusion() {
        System.out.println("开始处理绿幕数字人PPT融合任务...");
        
        if (!isFFmpegAvailable()) {
            System.err.println("错误: FFmpeg不可用，请确保已安装并添加到系统PATH中");
            return;
        }
        
        java.util.Map<String, String> paths = getFilePaths();
        
        // 检查输入文件是否存在
        if (!new File(paths.get("bg")).exists()) {
            System.err.println("错误: 背景图片不存在 - " + paths.get("bg"));
            return;
        }
        
        if (!new File(paths.get("result_video")).exists()) {
            System.err.println("错误: 数字人视频不存在 - " + paths.get("result_video"));
            return;
        }
        
        try {
            // 获取视频和背景图片信息
            VideoInfo videoInfo = getVideoInfo(paths.get("result_video"));
            VideoInfo bgInfo = getbgInfo(paths.get("bg"));
            
            System.out.println("数字人视频参数: 分辨率=" + videoInfo.width + "x" + videoInfo.height);
            System.out.println("背景图片参数: 分辨率=" + bgInfo.width + "x" + bgInfo.height);

            // 计算数字人参数
            int digitalHumanWidth = 400;
            // 保持数字人宽高比，基于原始视频比例
            int digitalHumanHeight = (int) (((double) videoInfo.height / videoInfo.width) * digitalHumanWidth);
            int posX = bgInfo.width - digitalHumanWidth;
            int posY = bgInfo.height - digitalHumanHeight;

            System.out.println("数字人大小: " + digitalHumanWidth + "x" + digitalHumanHeight);
            System.out.println("数字人位置: (" + posX + ", " + posY + ")");
            
            processGreenScreenDigitalHumanFusionInternal(
                paths.get("bg"),
                paths.get("result_video"),
                paths.get("output"),
                digitalHumanWidth,
                digitalHumanHeight,
                posX,
                posY,
                bgInfo
            );
            
        } catch (Exception e) {
            System.err.println("处理过程中发生错误: " + e.getMessage());
            e.printStackTrace();
        }
    }
    
    /**
     * 处理绿幕数字人PPT融合任务 - 参数化版本
     * @param bgPath 背景图片路径
     * @param resultVideoPath 数字人视频路径
     * @param outputPath 输出视频路径
     * @param digitalHumanWidth 数字人宽度
     * @param digitalHumanHeight 数字人高度
     * @param posX 数字人X坐标位置
     * @param posY 数字人Y坐标位置
     */
    public void processGreenScreenDigitalHumanFusion(
            String bgPath,
            String resultVideoPath,
            String outputPath,
            int digitalHumanWidth,
            int digitalHumanHeight,
            int posX,
            int posY) {
        
        System.out.println("开始处理绿幕数字人PPT融合任务...");
        
        if (!isFFmpegAvailable()) {
            System.err.println("错误: FFmpeg不可用，请确保已安装并添加到系统PATH中");
            return;
        }
        
        // 检查输入文件是否存在
        if (!new File(bgPath).exists()) {
            System.err.println("错误: 背景图片不存在 - " + bgPath);
            return;
        }
        
        if (!new File(resultVideoPath).exists()) {
            System.err.println("错误: 数字人视频不存在 - " + resultVideoPath);
            return;
        }
        
        try {
            // 获取背景图片信息
            VideoInfo bgInfo = getbgInfo(bgPath);
            
            System.out.println("背景图片参数: 分辨率=" + bgInfo.width + "x" + bgInfo.height);
            System.out.println("数字人大小: " + digitalHumanWidth + "x" + digitalHumanHeight);
            System.out.println("数字人位置: (" + posX + ", " + posY + ")");
            
            processGreenScreenDigitalHumanFusionInternal(
                bgPath,
                resultVideoPath,
                outputPath,
                digitalHumanWidth,
                digitalHumanHeight,
                posX,
                posY,
                bgInfo
            );
            
        } catch (Exception e) {
            System.err.println("处理过程中发生错误: " + e.getMessage());
            e.printStackTrace();
        }
    }
    
    /**
     * 内部处理方法，执行实际的FFmpeg命令
     */
    private void processGreenScreenDigitalHumanFusionInternal(
            String bgPath,
            String resultVideoPath,
            String outputPath,
            int digitalHumanWidth,
            int digitalHumanHeight,
            int posX,
            int posY,
            VideoInfo bgInfo) throws IOException, InterruptedException {
        
        // 构建FFmpeg命令
        List<String> command = new ArrayList<>();
        command.add("ffmpeg");
        command.add("-i");
		// 背景图片
        command.add(bgPath);
        command.add("-i");
		// 数字人视频
        command.add(resultVideoPath);
        
        // 设置背景图片循环
        command.add("-loop");
        command.add("1");

        // 设置滤镜_complex参数
        StringBuilder filterComplex = new StringBuilder();
        // 背景图片缩放到合适尺寸
        filterComplex.append("[0:v]scale=").append(bgInfo.width).append(":").append(bgInfo.height).append("[bg];");
        // 数字人视频先缩放再去除绿色背景
        filterComplex.append("[1:v]scale=").append(digitalHumanWidth).append(":").append(digitalHumanHeight).append(",chromakey=0x00b121:0.1:0.1[scaled_dh];");
        // 将处理后的数字人叠加到背景上
        filterComplex.append("[bg][scaled_dh]overlay=").append(posX).append(":").append(posY);
        
        command.add("-filter_complex");
        command.add(filterComplex.toString());
        
        // 设置输出参数
        command.add("-c:a");
		// 复制音频轨道
        command.add("copy");
		// 覆盖输出文件
        command.add("-y");
        command.add(outputPath);
        
        // 执行FFmpeg命令
        executeFFmpegCommand(command);
        
        System.out.println("绿幕数字人PPT融合任务完成！输出文件: " + outputPath);
        
        // 验证输出文件
        File outputFile = new File(outputPath);
        if (outputFile.exists()) {
            double fileSize = outputFile.length() / (1024.0 * 1024.0);
            System.out.printf("输出文件大小: %.2f MB%n", fileSize);
        } else {
            System.err.println("警告: 输出文件可能未成功创建");
        }
    }
    
    public static void main(String[] args) throws IOException, InterruptedException {
		String bgPath = "D:\\workspace\\git_ai\\ruoyi-ai\\bg.png";
		String resultPath =	"D:\\workspace\\git_ai\\ruoyi-ai\\result.mp4";
		String outputPath =	"D:\\workspace\\git_ai\\ruoyi-ai\\output_" + LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMdd_HHmmss")) + ".mp4";

        FFMpegDigitalHumanFusionProcessor2 processor = new FFMpegDigitalHumanFusionProcessor2();
		// 获取视频和背景图片信息
		VideoInfo videoInfo = processor.getVideoInfo(resultPath);
		VideoInfo bgInfo = processor.getbgInfo(bgPath);

		// 计算数字人参数
		int digitalHumanWidth = 400;
		// 保持数字人宽高比，基于原始视频比例
		int digitalHumanHeight = (int) (((double) videoInfo.height / videoInfo.width) * digitalHumanWidth);
		int posX = bgInfo.width - digitalHumanWidth;
		int posY = bgInfo.height - digitalHumanHeight;

//        processor.processGreenScreenDigitalHumanFusion();
		processor.processGreenScreenDigitalHumanFusion(
			"D:\\workspace\\git_ai\\ruoyi-ai\\bg.png",
			"D:\\workspace\\git_ai\\ruoyi-ai\\result.mp4",
			"D:\\workspace\\git_ai\\ruoyi-ai\\output_" + LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMdd_HHmmss")) + ".mp4",
			// width
			digitalHumanWidth,
			// height
			digitalHumanHeight,
			// posX
			posX,
			// posY
			posY
		);
    }
    
    // 视频信息内部类
    private static class VideoInfo {
        int width, height;
        
        public VideoInfo(int width, int height) {
            this.width = width;
            this.height = height;
        }
    }
}
